package com.gss.plugin.doc.handler;

import com.gss.plugin.doc.properties.Knife4jProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import springfox.documentation.service.*;
import springfox.documentation.spring.web.DocumentationCache;
import springfox.documentation.spring.web.plugins.Docket;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

/**
 * @author: DYang
 * @since: 2023/8/23
 * @description:
 */
@Component
public class ApiToMenuHandler implements CommandLineRunner {

    @Autowired
    private DataSource dataSource;
    @Autowired
    private Knife4jProperties knife4jProperties;
    @Autowired
    private DocumentationCache documentationCache;
    @Autowired
    private Docket docket;

    @Override
    public void run(String... args) throws Exception {
        this.apiToDbHandle();
    }


    /**
     * 启动后，获取所有的api,将所有接口api存入数据库
     */
//    @PostConstruct
    public void apiToDbHandle(){
        Connection conn = null;
        try {
            boolean enableSaveDb = knife4jProperties.isEnableSaveDb();
            String insertApiSql = knife4jProperties.getInsertApiSql();
            if (!enableSaveDb || !StringUtils.hasText(insertApiSql) || dataSource == null) {
                return;
            }
            conn = dataSource.getConnection();
            // 获取swagger 所有的接口资源
            Documentation documentation = documentationCache.documentationByGroup(docket.getGroupName());
            if (documentation == null || CollectionUtils.isEmpty(documentation.getApiListings())) {
                return;
            }
            Map<String, List<ApiListing>> apiMap = documentation.getApiListings();
            for (Map.Entry<String, List<ApiListing>> entry : apiMap.entrySet()) {
                List<ApiListing> apiList = entry.getValue();
                if (apiList == null || apiList.size() == 0) {
                    continue;
                }
                // 接口模块
                for (ApiListing apiListing : apiList) {
                    // 模块
                    Map<String, Object> map = this.insertModule(apiListing);
                    this.saveApiToDb(conn,map);
                    // 接口
                    List<ApiDescription> apis = apiListing.getApis();
                    if (apis == null || apis.size() == 0) {
                        continue;
                    }
                    for (ApiDescription api : apis) {
                        map = this.insertApi(api);
                        this.saveApiToDb(conn,map);
                    }
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            this.close(conn,null,null);
        }
    }

    /**
     * 新增接口
     * @param api
     * @return
     */
    private Map<String, Object> insertApi(ApiDescription api) {
        String url = api.getPath();
        String route = url.substring(1).replace("/",":");
        // 0: 菜单 1:目录
        int menuType = 1;
        String menuName = url;
        List<Operation> operations = api.getOperations();
        if (operations != null && operations.size()  > 0) {
            Operation operation = operations.get(0);
            menuName = operation.getSummary();
        }
        Map<String,Object> map = new HashMap<>();
        map.put("menuName",menuName);
        map.put("menuType",menuType);
        map.put("route",route);
        map.put("url",url);
        map.put("createTime",new Date());
        map.put("updateTime",new Date());
        return map;
    }

    /**
     * 新增接口
     * @param apiListing
     */
    private Map<String,Object> insertModule(ApiListing apiListing) {
        String url = apiListing.getResourcePath();
        String route = url.substring(1);
        // 0: 菜单 1:目录
        int menuType = 0;
        String menuName = url;
        Set<Tag> tags = apiListing.getTags();
        if (tags.size() > 0) {
            Tag tag = new ArrayList<>(tags).get(0);
            menuName = tag.getName();
        }
        Map<String,Object> map = new HashMap<>();
        map.put("menuName",menuName);
        map.put("menuType",menuType);
        map.put("route",route);
        map.put("url",url);
        map.put("createTime",new Date());
        map.put("updateTime",new Date());
        return map;
    }

    /**
     * 存储数据到数据库
     * @param conn
     * @param paramMap
     */
    private void saveApiToDb(Connection conn,Map<String,Object> paramMap){
        PreparedStatement ps = null;
        try {
            String sql = knife4jProperties.getInsertApiSql();

            ps = conn.prepareStatement(sql);
            ps.setString(1, (String) paramMap.get("menuName"));
            ps.setInt(2, (int) paramMap.get("menuType"));
            ps.setString(3, (String) paramMap.get("route"));
            ps.setString(4, (String) paramMap.get("url"));

            ps.execute();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            this.close(null,ps,null);
        }
    }

    /**
     * 释放资源
     * @param conn
     * @param ps
     * @param rs
     */
    private void close(Connection conn, PreparedStatement ps, ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


}
